
enum
{
	CVAR_INT = 1<<0,
	CVAR_FLOAT = 1<<1,
	CVAR_BOOL = 1<<2,
	CVAR_READ_ONLY = 1<<3,
	CVAR_MODIFIER = 1<<4,
	CVAR_POINTER = 1<<5,
};

class CVar
{
public:
	CVar(const char* name);
	CVar(const char* name, const char* default_value, uint32_t flags, const char* description);
	CVar(const char* name, const char* default_value, float valueMin, float valueMax, uint32_t flags, const char* description);
	CVar(const char* name, const char* default_value, const char** allowed_values, uint32_t flags, const char* description);

	const char*				GetName( void ) const { return mInternalVar->mName; }
	int								GetFlags( void ) const { return mInternalVar->mFlags; }
	const char*				GetDescription( void ) const { return mInternalVar->mDescription; }
	float							GetMinValue( void ) const { return mInternalVar->mValueMin; }
	float							GetMaxValue( void ) const { return mInternalVar->mValueMax; }
	const char**			GetValueStrings( void ) const { return mValueStrings; }

	const char *			GetString( void ) const { return mInternalVar->mValue; }
	bool							GetBool( void ) const { return ( mInternalVar->mIntValue != 0 ); }
	int								GetInteger( void ) const { return mInternalVar->mIntValue; }
	float							GetFloat( void ) const { return mInternalVar->mFloatValue; }
private:
	const char* mName;
	const char* mDefaultValue;
	const char* mDescription;
	uint32_t mFlags;
	float mValueMin;
	float mValueMax;
	const char** mValueStrings;
	CVar* mInternalVar;
	CVar* mNext;

	const char* mValue; /// bo może być z mValueStrings'ów, albo takie rzeczy

	float mFloatValue;
	int mIntValue;
	eastl::string mStringValue;

	void UpdateValue();

	void Init(const char* name, const char* defstr, float fltmax, float fltmin, const char** allowed, uint32_t flags, const char* desc);

	static CVar* mStaticCVars;
	static void RegisterStaticCVars();

	friend class CVarManagerClass;
};
CVar* CVar::mStaticCVars = 0;

class CVarManagerClass
{
public:
	eastl::hash_map<eastl::string, CVar*> CVars;

	void Register(CVar* var);
};

void CVarManagerClass::Register( CVar* var )
{
	eastl::hash_map<eastl::string, CVar*>::iterator existing = CVars.find_as(var->GetName());
	if (existing != CVars.end())
	{
		if (var->GetFlags() & CVAR_POINTER)
			var->mInternalVar = existing->second;
		else
			;//log->Error("CVar with name %s redeclared", var->GetName(), Severity::CodeBug);

		return;
	}

	CVars[var->GetName()] = var;
}

CVarManagerClass* CVarManager = new CVarManagerClass;

CVar::CVar( const char* name, const char* default_value, uint32_t flags, const char* description )
{
	Init(name, default_value, -1, 1, 0, flags, description);
}

CVar::CVar( const char* name, const char* default_value, float valueMin, float valueMax, uint32_t flags, const char* description )
{
	Init(name, default_value, valueMin, valueMax, 0, flags, description);
}

void CVar::Init( const char* name, const char* defstr, float fltmax, float fltmin, const char** allowed, uint32_t flags, const char* desc )
{
	mName = name;
	mDefaultValue = defstr;
	mValueMax = fltmax;
	mValueMin = fltmin;
	mValueStrings = allowed;
	mFlags = flags;
	mInternalVar = this;

	mValue = defstr;
	mIntValue = 0;
	mFloatValue = 0;

	if (mStaticCVars != (CVar*)0xFFFFFFFF)
	{
		mNext = mStaticCVars;
		mStaticCVars = this;
	} else
	{
		CVarManager->Register(this);
	}
}

void CVar::RegisterStaticCVars()
{
	if ( mStaticCVars != (CVar*)0xFFFFFFFF ) 
	{
		for ( CVar *cvar = mStaticCVars; cvar; cvar = cvar->mNext ) {
			CVarManager->Register( cvar );
		}
		mStaticCVars = (CVar*)0xFFFFFFFF;
	}
}

void CVar::UpdateValue()
{

}

CVar g_fullscreen("g_fullscreen", "false", CVAR_BOOL, "fullscreen");
CVar g_width("g_width", "640", 640, 1280, CVAR_FLOAT, "screen width");
CVar g_height("g_height", "480", 480, 1024, CVAR_FLOAT, "screen height");
